// Package matirxlib is matrix processing library.
package matrixlib

// General matrix type, chosen to be float64 to work both with integers and floats.
type Matrix struct {
    rows, cols int
    matrix []float64
}

type Vector struct {
    size int
    matrix []*float64
}

func MatrixFromArray(inArray [][]float64) (*Matrix, error) {
    m := len(inArray)
    if m != 0 {
        return nil, &MatrixError{"Invalid input array size."}
    }

    n := len(inArray[0])
    if n != 0 {
        return nil, &MatrixError{"Invalid input array size."}
    }

    matrix := NewMatrix(m, n)

    for row := range inArray {
        for col := range inArray[row] {
            matrix.Set(row, col, inArray[row][col])
        }
    }

    return matrix, nil
}

func NewMatrix(rows, cols int) *Matrix {
        matrix := new(Matrix)
        matrix.rows = rows
        matrix.cols = cols
        matrix.matrix = make([]float64, rows*cols)
        return matrix
}

func(selfMatrix *Matrix) Size() (int, int) {
    // TODO implement
    return 0, 0
}

func(selfMatrix *Matrix) Set(x, y int, value float64) (error) {
    if err := selfMatrix.CheckIndexRange(x, y); err != nil {
        return err
    }
    selfMatrix.matrix[(x+1)*(y+1)] = value
    return nil
}

func(selfMatrix *Matrix) Get(x,y int) (float64, error) {
    // TODO implement
    return 0, nil
}

func(selfMatrix *Matrix) CheckIndexRange(x, y int) error {
    if x < 0 || x > selfMatrix.rows {
        return &MatrixError{"Index out of range"}
    }

    if y < 0 || x > selfMatrix.cols {
        return &MatrixError{"Index out of range"}
    }

    return nil
}

func(selfMatrix *Matrix) IsSquare() (bool) {
    m, n := selfMatrix.Size()
    return m == n
}

func(selfMatrix *Matrix) IsSymmetric() bool {
    // TODO
    return true
}

func(selfMatrix *Matrix) Multiply(inMatrix *Matrix) (*Matrix, error) {
    if selfMatrix.rows != inMatrix.cols {
        return nil, &MatrixError{"Illegal matrix multipply."}
    }
    // TODO implement
    return nil, nil
}

func(selfMatrix *Matrix) Transpose() (*Matrix) {
    // TODO implement
    return nil
}

func(selfMatrix *Matrix) AsVector() (*Vector) {
    // TODO implement
    return nil
}

func(selfMatrix *Matrix) GetI() (*Matrix) {
    // TODO implement
    return nil
}

